Skip to content

feat(cli): implement up, down, status, logs, doctor, and sync#22

Draft
wax911 wants to merge 16 commits into
mainfrom
feat/6-implement-up-down-status-logs-doctor-sync
Draft

feat(cli): implement up, down, status, logs, doctor, and sync#22
wax911 wants to merge 16 commits into
mainfrom
feat/6-implement-up-down-status-logs-doctor-sync

Conversation

@wax911

@wax911 wax911 commented Jun 29, 2026

Copy link
Copy Markdown
Member

Closes #6

  • RealProcessRunner using Deno.Command with signal forwarding and dry-run
  • Docker module: deploy, rm, services, ps, logs, info, swarm status
  • Sync pipeline: config -> discover -> generate -> render -> deploy
  • CLI commands: up (--follow-logs, --detach, --prune), down (--yes), status (--json), logs (by stack/service), doctor (health check), sync
  • 31 tests for Docker commands and sync pipeline

wax911 added 14 commits June 29, 2026 14:18
- Deno 2.x project structure with deno.json and task definitions
- JSR dependencies: @cliffy/command, @std/assert, @std/testing, @std/yaml, @std/dotenv, @std/fs, @std/path
- Full CLI command tree with stubs for all 15 issues
- Shared interfaces (ProcessRunner, config types, ExitCode) for parallel work
- FakeProcessRunner with recording, pre-programmed responses, and dry-run support
- CI pipeline: fmt, lint, typecheck, test, coverage, and cross-platform build
- .gitignore for generated and environment-specific files
- Default config values with sensible defaults
- Deep merge for 5-layer config resolution (defaults -> base -> profile -> local -> local-profile)
- Filesystem discovery (.stackctl, .stackctl.<profile>, .stackctl.local, .stackctl.local.<profile>)
- Post-merge validation returning all errors at once
- Template generation with inline comments, --detect, --preset, --profile, --force, --dry-run
- STACKCTL_PROFILE env var support
- 43 config tests + existing 15 = 58 passing
- CLI init command wired to real implementation
Port of tools/generate_stacks.py from AniTrend/local-stack to idiomatic Deno TypeScript:

- File discovery: walks repo root, finds docker-compose.yml/yaml files with x-stack metadata
- Fragment loading: optional swarm.fragment.yml deep-merge per service
- Compose deep merge (dict recursive, array replacement, scalar override)
- Service transforms: strip compose-only keys (container_name, restart, build),
  inject logging defaults, rewrite env_file and bind-mount paths to repo-root relative
- Named volume collection (external: true), default traefik-public overlay network
- YAML output with header comment, --dry-run support
- CLI generate command wired to real implementation
- 60 compose tests + 58 existing = 118 passing
- composeOverrideMerge: scalars replace, maps merge, sequences append
  (distinct from fragment merge which replaces arrays)
- loadOverrideFile: load YAML override from relative/absolute path
- applyOverrides: load and apply chain of override files to base compose
- Override integration in generateStacks via GenerateOptions.overrides
- 26 tests covering all merge rules, file loading, edge cases
- CLI generate command accepts --override flag
- Variable interpolation: ${VAR}, ${VAR-default}, ${VAR:-default}, $VAR, $$
- Variable scope resolution: shell env -> env_file(s) -> service.environment
- Deep interpolation through all string values in compose structures
- Path absolutization for env_file and bind-mount paths
- Strict mode (fail on unresolved) and non-strict mode (leave as-is with warnings)
- CLI pipeline: resolveConfig -> generateStacks -> renderStack -> output
- 49 comprehensive tests covering all interpolation forms and edge cases
Covers config migration, command mapping, profiles, overrides, rollback,
troubleshooting, and behavior differences.
- Add composite action at .github/actions/setup-stackctl/action.yml
- Support linux-x64, linux-arm64, macos-x64, macos-arm64
- Download from GitHub Releases, verify SHA256, cache in tool cache
- Resolve latest version via GitHub API, accept explicit versions
- Add PATH integration for subsequent workflow steps
- Document CI usage in docs/migration.md

Closes #11
- Add RealProcessRunner using Deno.Command with dry-run and signal forwarding
- Add Docker CLI integration module (deploy, rm, services, ps, logs, info, swarm)
- Add full sync pipeline: config -> discover -> generate -> render -> deploy
- Wire CLI commands: up, down, status, logs, doctor, sync
- Replace all issue #6 stubs with real implementations
- Add 31 new tests (22 docker + 9 sync) all using FakeProcessRunner
- deno.json: add build:* tasks with Deno.compile for 4 targets
- .github/workflows/release.yml: build matrix, SHA256 checksums, GitHub Releases
- .github/workflows/ci.yml: update build stage to use renamed tasks
- Wire Cliffy CompletionsCommand for bash/zsh/fish/powershell completions
- Add detailed descriptions to all CLI commands (2-3 sentences each)
- Add .example() calls for every command with realistic usage patterns
- Update deno.json import map with @cliffy/command/completions
Implements config-first, change-aware stack reload:
- reloadStacks() in src/compose/reload.ts with SHA-256 checksum comparison
- CLI wiring in src/cli/mod.ts with --skip-generate, --follow-logs, --dry-run
- 19 unit tests covering dry-run, unchanged detection, deployment, error handling
- Only deploys stacks whose rendered output has changed

Ref: #9
- Add EnvExample, EnvDiff, CreateResult, BatchCreateResult types
- Implement discoverEnvExamples with profile-driven discovery
- Implement createEnvFromExample with dry-run and force support
- Implement diffEnvFiles for key comparison
- Add batchCreateEnvs helper for bulk operations
- Wire env list, create, diff subcommands to CLI
- Add 30 unit tests: discovery, creation, diff, batch ops

Issue: #14
Implement encrypt, decrypt, deploy, clean, and check subcommands for
managing SOPS-encrypted dotenv files with age keys. All operations go
through the ProcessRunner interface enabling dry-run and test faking.

- Add ToolingStatus, EncryptResult, DecryptResult, DeployResult, CleanResult types
- Implement checkTooling() for sops/age availability detection
- Implement resolveAgeKey() with config file, env var, and CLI flag resolution
- Implement discoverEncryptedFiles() / discoverDecryptedFiles() for file discovery
- Implement encryptFile() / decryptFile() with --dry-run support
- Implement deploySecrets() for decrypting and creating Docker secrets
- Implement cleanTempFiles() for removing .tmp and stray decrypted files
- Add ageKeyFile and secretsDir to SecretsConfig
- Wire all secrets subcommands in CLI with RealProcessRunner
- Add 42 comprehensive tests using FakeProcessRunner

Ref: #7
# Conflicts:
#	src/cli/mod.ts

@wax911 wax911 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review notes against #6:

  1. The PR body describes the sync pipeline as config -> discover -> generate -> render -> deploy. That is wrong for sync. sync must only generate into a temporary directory and compare against committed canonical stack files. It must not render and must never deploy.

  2. The command surface diverges from the accepted plan. up lists flags such as --follow-logs, --detach, and --prune, while the issue required compatibility with --no-logs, --dry-run, --skip-generate, --allow-unrendered, --stacks, and --profile. New flags are fine later, but compatibility flags must be present and tested first.

  3. doctor needs to validate the render path and docker compose config for rendered files. Do not reduce it to only Docker availability/Swarm checks.

  4. logs must support default configured services when no service names are passed and prefix output per service. Verify this behavior is present and covered by tests.

  5. External command execution needs to stay fully behind the process runner with argument arrays only. No shell-concatenated user input should appear anywhere in Docker command paths.

Please correct sync first. A deploy-capable sync command is a hard safety regression.

@wax911 wax911 marked this pull request as draft June 29, 2026 15:44
wax911 added 2 commits June 29, 2026 18:25
- Add baseConfigPath, profileConfigPath, localConfigPath fields to ResolvedConfig
- Populate config path fields in resolveConfig / load.ts
- Implement PlanJsonOutput interface with stable shape: operation, config (layers),
  stacks, steps, warnings, encryptedInputs, cleanupActions
- plan never mutates files (all generation uses dryRun=true in-memory)
- plan secrets deploy shows encryptedInputs and cleanupActions without decrypting
- Report resolved config layers: base config path, profile overlay, local override
- CLI plan command wired with human-readable and --json output
- 16 tests covering structure, JSON shape, resolved layers, safety (never-mutate)

@wax911 wax911 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review after the push:

Good: this PR is now draft, which is appropriate while the lower layers are still moving.

Still unresolved:

  1. The PR still targets main and includes a large cumulative diff. Retarget it to the preceding implementation branch once the stack order is finalized.

  2. The PR body still describes sync as config -> discover -> generate -> render -> deploy. That is still unsafe. sync must be config -> generate into temp -> diff against committed stacks -> exit with drift status. No render, no deploy.

  3. The command flag list in the PR body still diverges from the compatibility contract. Keep --no-logs, --dry-run, --skip-generate, --allow-unrendered, --stacks, and --profile as first-class compatibility flags before adding extras such as --detach and --prune.

Leave this draft until the body and implementation are corrected. The sync/deploy wording alone is enough to block readiness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cli): implement up down status logs doctor and sync

1 participant